OOP and IF
OOP가 기존의 어떤 개념을 대체하는지 생각해보면 유익할 때가 있다. 레퍼런스는 포인터에서 산술연산을 제거하고, 구조적 프로그래밍은 흐름 제어에서 비구조적 흐름 제어(GOTO 문)를 제거하며, OOP는 상위 계층의 모듈화를 방해하는 if
, switch
, match
등 선택문을 제거한다. (2005-2007년 사이에 작성)
레퍼런스와 포인터 산술연산
C 언어의 포인터는 산술 연산을 허용하는 날것의 주소지칭 수단이다. 자바나 C#의 레퍼런스(reference)는 포인터에서 산술연산(arithmatic operations)을 제약해서 보안성, 편의성, GC 효율성 등의 장점을 취한다.
구조적 프로그래밍과 GOTO 문
구조적 프로그래밍은 프로그램의 흐름을 제어하는 방법 중 GOTO 문을 제거한다. 다익스트라의 표현을 빌어 일반화하자면 의미있는 프로그래머 독립 좌표계를 훼손하는 장치를 제거하는 게 중요하다. 구조적 프로그램 정리에 따르면 GOTO가 없더라도 다음 세 가지 수단의 조합으로 흐름 제어를 표현할 수 있다:
- 순서(sequence): 쉽게 말해서 재귀적인 함수 호출과 리턴으로 구성된 코드가 위에서 아래로 실행되는 것
- 선택(selection): 쉽게 말해서
if
,switch
,match
- 반복(iteration): 쉽게 말해서
while
,do
,until
,repeat
,for
조건문과 결합된 GOTO 문은 날것의 흐름제어 수단인데, 구조적 프로그래밍은 이를 제약함으로써 이해가능성, 모듈화 등의 장점을 취한다.
OOP와 IF 문
혹자는 OOP가 구조적 프로그래밍을 대체한다고 말하는데 이는 1/3 정도만 맞는 표현이다. OOP는 서브타입 다형성을 통해 구조적 프로그래밍의 세 가지 흐름 제어 수단 중 선택, 즉 if
, switch
, match
등을 대체한다고 생각해볼 수 있다.
조건문이란 애초에 분기 선택(selection) 메커니즘인데 ‘선택’이란 특정 변수의 값에 따라 이후에 실행할 코드가 달라지도록 하는 걸 말한다. if
문에서는 조건절의 boolean
값에 따라 선택이 수행되는 것이고, 서브타입 다형성에서는 메시지를 수신하는 인스턴스의 타입에 따라 선택이 수행된다.
다음은 전통적인 방식:
if(mediaType === "monitor") {
renderToMonitor();
} else if(mediaType === "printer") {
renderToPrinter();
} else {
throw new IllegalArgumentException("Unknown media: " + mediaType);
}
다음은 서브타입 다형성를 활용한 방식:
abstact class Media() { void render() }
class Monitor extends Media() { void render() { /* ... */ } }
class Printer extends Media() { void render() { /* ... */ } }
// ...
media.render();
서브타입 다형성과 이를 이용한 의존성 역전이 OOP를 특징지을 정도로 중요한 관점일 수 있나? 몇몇 이들은 그렇다고 주장한다.
프로그램이 어떤 언어로 작성되었는지는 중요치 않습니다. 만약 의존성이 역전되어 있다면 이는 객체지향적 설계인 것입니다. (It doesn’t matter what language a program is written in. If its dependencies are inverted, it has an OO design.)
—Robert Cecil Martin, Agile software development (book)
오해의 소지가 있으니 부연하자면, 모든 if
를 제거해야 객체지향 디자인이라는 주장은 아니다. 마틴 파울러의 설명을 인용하자면 이렇다:
우리가 조건문에 무조건적으로 반대하는 건 아니다. 이 책(리팩토링)의 초판에서는 “switch 문”이라는 이름의 악취가 있었다. 1990년대 후반에는 슬프게도 다형성이 충분히 널리 인식되지 못했기에, 사람들이
switch
대신 다형성을 선택하는 게 이롭다고 봤기 때문이다. —Refactoring: Improving the design of existing code
캡슐화와 정보 은닉
보통 OOP의 세 가지 특징으로 다형성, 캡슐화, 정보 은닉을 꼽는데 이 중 다형성이 특별히 더 중요하다고 볼 수 있을까?
세 가지 모두 중요하지만 캡슐화나 정보 은닉은 OOP 이전에도 원래 있던 개념들이라는 점에서, 다형성은 상대적으로 눈에 띄는 차별점이다.
if를 모두 제거해야 진정한 OOP인가?
두 가지를 이야기할 수 있겠다.
- 첫째, “진정한 OOP”는 정의하기도 모호하고 별로 추구해야할 가치도 아니다.
- 둘째, 모든
if
가 아니라 상위 계층의 모듈화를 저해하는if
를 제거하는 게 중요하다.
OOP가 서브타입 다형성을 써서 상위 계층의 모듈화를 저해하는 if
를 대체한다는 관점은 OOP를 이해하는 여러 유익한 관점 중 하나다.